home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / include / linux / sunrpc / cache.h < prev    next >
C/C++ Source or Header  |  2005-10-13  |  11KB  |  322 lines

  1. /*
  2.  * include/linux/sunrpc/cache.h
  3.  *
  4.  * Generic code for various authentication-related caches
  5.  * used by sunrpc clients and servers.
  6.  *
  7.  * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
  8.  *
  9.  * Released under terms in GPL version 2.  See COPYING.
  10.  *
  11.  */
  12.  
  13. #ifndef _LINUX_SUNRPC_CACHE_H_
  14. #define _LINUX_SUNRPC_CACHE_H_
  15.  
  16. #include <linux/slab.h>
  17. #include <asm/atomic.h>
  18. #include <linux/proc_fs.h>
  19.  
  20. /*
  21.  * Each cache requires:
  22.  *  - A 'struct cache_detail' which contains information specific to the cache
  23.  *    for common code to use.
  24.  *  - An item structure that must contain a "struct cache_head"
  25.  *  - A lookup function defined using DefineCacheLookup
  26.  *  - A 'put' function that can release a cache item. It will only
  27.  *    be called after cache_put has succeed, so there are guarantee
  28.  *    to be no references.
  29.  *  - A function to calculate a hash of an item's key.
  30.  *
  31.  * as well as assorted code fragments (e.g. compare keys) and numbers
  32.  * (e.g. hash size, goal_age, etc).
  33.  *
  34.  * Each cache must be registered so that it can be cleaned regularly.
  35.  * When the cache is unregistered, it is flushed completely.
  36.  *
  37.  * Entries have a ref count and a 'hashed' flag which counts the existance
  38.  * in the hash table.
  39.  * We only expire entries when refcount is zero.
  40.  * Existance in the cache is not measured in refcount but rather in
  41.  * CACHE_HASHED flag.
  42.  */
  43.  
  44. /* Every cache item has a common header that is used
  45.  * for expiring and refreshing entries.
  46.  * 
  47.  */
  48. struct cache_head {
  49.     struct cache_head * next;
  50.     time_t        expiry_time;    /* After time time, don't use the data */
  51.     time_t        last_refresh;   /* If CACHE_PENDING, this is when upcall 
  52.                      * was sent, else this is when update was received
  53.                      */
  54.     atomic_t     refcnt;
  55.     unsigned long    flags;
  56. };
  57. #define    CACHE_VALID    0    /* Entry contains valid data */
  58. #define    CACHE_NEGATIVE    1    /* Negative entry - there is no match for the key */
  59. #define    CACHE_PENDING    2    /* An upcall has been sent but no reply received yet*/
  60. #define    CACHE_HASHED    3    /* Entry is in a hash table */
  61.  
  62. #define    CACHE_NEW_EXPIRY 120    /* keep new things pending confirmation for 120 seconds */
  63.  
  64. struct cache_detail {
  65.     int            hash_size;
  66.     struct cache_head **    hash_table;
  67.     rwlock_t        hash_lock;
  68.  
  69.     atomic_t        inuse; /* active user-space update or lookup */
  70.  
  71.     char            *name;
  72.     void            (*cache_put)(struct cache_head *,
  73.                          struct cache_detail*);
  74.  
  75.     void            (*cache_request)(struct cache_detail *cd,
  76.                          struct cache_head *h,
  77.                          char **bpp, int *blen);
  78.     int            (*cache_parse)(struct cache_detail *,
  79.                            char *buf, int len);
  80.  
  81.     int            (*cache_show)(struct seq_file *m,
  82.                           struct cache_detail *cd,
  83.                           struct cache_head *h);
  84.  
  85.     /* fields below this comment are for internal use
  86.      * and should not be touched by cache owners
  87.      */
  88.     time_t            flush_time;        /* flush all cache items with last_refresh
  89.                              * earlier than this */
  90.     struct list_head    others;
  91.     time_t            nextcheck;
  92.     int            entries;
  93.  
  94.     /* fields for communication over channel */
  95.     struct list_head    queue;
  96.     struct proc_dir_entry    *proc_ent;
  97.     struct proc_dir_entry   *flush_ent, *channel_ent, *content_ent;
  98.  
  99.     atomic_t        readers;        /* how many time is /chennel open */
  100.     time_t            last_close;        /* if no readers, when did last close */
  101.     time_t            last_warn;        /* when we last warned about no readers */
  102.     void            (*warn_no_listener)(struct cache_detail *cd);
  103. };
  104.  
  105.  
  106. /* this must be embedded in any request structure that
  107.  * identifies an object that will want a callback on
  108.  * a cache fill
  109.  */
  110. struct cache_req {
  111.     struct cache_deferred_req *(*defer)(struct cache_req *req);
  112. };
  113. /* this must be embedded in a deferred_request that is being
  114.  * delayed awaiting cache-fill
  115.  */
  116. struct cache_deferred_req {
  117.     struct list_head    hash;    /* on hash chain */
  118.     struct list_head    recent; /* on fifo */
  119.     struct cache_head    *item;  /* cache item we wait on */
  120.     time_t            recv_time;
  121.     void            *owner; /* we might need to discard all defered requests
  122.                      * owned by someone */
  123.     void            (*revisit)(struct cache_deferred_req *req,
  124.                        int too_many);
  125. };
  126.  
  127. /*
  128.  * just like a template in C++, this macro does cache lookup
  129.  * for us.
  130.  * The function is passed some sort of HANDLE from which a cache_detail
  131.  * structure can be determined (via SETUP, DETAIL), a template
  132.  * cache entry (type RTN*), and a "set" flag.  Using the HASHFN and the 
  133.  * TEST, the function will try to find a matching cache entry in the cache.
  134.  * If "set" == 0 :
  135.  *    If an entry is found, it is returned
  136.  *    If no entry is found, a new non-VALID entry is created.
  137.  * If "set" == 1 and INPLACE == 0 :
  138.  *    If no entry is found a new one is inserted with data from "template"
  139.  *    If a non-CACHE_VALID entry is found, it is updated from template using UPDATE
  140.  *    If a CACHE_VALID entry is found, a new entry is swapped in with data
  141.  *       from "template"
  142.  * If set == 1, and INPLACE == 1 :
  143.  *    As above, except that if a CACHE_VALID entry is found, we UPDATE in place
  144.  *       instead of swapping in a new entry.
  145.  *
  146.  * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not
  147.  * run but insteead CACHE_NEGATIVE is set in any new item.
  148.  
  149.  *  In any case, the new entry is returned with a reference count.
  150.  *
  151.  *    
  152.  * RTN is a struct type for a cache entry
  153.  * MEMBER is the member of the cache which is cache_head, which must be first
  154.  * FNAME is the name for the function    
  155.  * ARGS are arguments to function and must contain RTN *item, int set.  May
  156.  *   also contain something to be usedby SETUP or DETAIL to find cache_detail.
  157.  * SETUP  locates the cache detail and makes it available as...
  158.  * DETAIL identifies the cache detail, possibly set up by SETUP
  159.  * HASHFN returns a hash value of the cache entry "item"
  160.  * TEST  tests if "tmp" matches "item"
  161.  * INIT copies key information from "item" to "new"
  162.  * UPDATE copies content information from "item" to "tmp"
  163.  * INPLACE is true if updates can happen inplace rather than allocating a new structure
  164.  *
  165.  * WARNING: any substantial changes to this must be reflected in
  166.  *   net/sunrpc/svcauth.c(auth_domain_lookup)
  167.  *  which is a similar routine that is open-coded.
  168.  */
  169. #define DefineCacheLookup(RTN,MEMBER,FNAME,ARGS,SETUP,DETAIL,HASHFN,TEST,INIT,UPDATE,INPLACE)    \
  170. RTN *FNAME ARGS                                        \
  171. {                                            \
  172.     RTN *tmp, *new=NULL;                                \
  173.     struct cache_head **hp, **head;                            \
  174.     SETUP;                                        \
  175.     head = &(DETAIL)->hash_table[HASHFN];                        \
  176.  retry:                                            \
  177.     if (set||new) write_lock(&(DETAIL)->hash_lock);                    \
  178.     else read_lock(&(DETAIL)->hash_lock);                        \
  179.     for(hp=head; *hp != NULL; hp = &tmp->MEMBER.next) {                \
  180.         tmp = container_of(*hp, RTN, MEMBER);                    \
  181.         if (TEST) { /* found a match */                        \
  182.                                             \
  183.             if (set && !INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \
  184.                 break;                            \
  185.                                             \
  186.             if (new)                            \
  187.                 {INIT;}                            \
  188.             cache_get(&tmp->MEMBER);                    \
  189.             if (set) {                            \
  190.                 if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
  191.                 { /* need to swap in new */                \
  192.                     RTN *t2;                    \
  193.                                             \
  194.                     new->MEMBER.next = tmp->MEMBER.next;        \
  195.                     *hp = &new->MEMBER;                \
  196.                     tmp->MEMBER.next = NULL;            \
  197.                     set_bit(CACHE_HASHED, &new->MEMBER.flags);    \
  198.                     clear_bit(CACHE_HASHED, &tmp->MEMBER.flags);    \
  199.                     t2 = tmp; tmp = new; new = t2;            \
  200.                 }                            \
  201.                 if (test_bit(CACHE_NEGATIVE,  &item->MEMBER.flags))    \
  202.                     set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);    \
  203.                 else {                            \
  204.                     UPDATE;                        \
  205.                     clear_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);    \
  206.                 }                            \
  207.             }                                \
  208.             if (set||new) write_unlock(&(DETAIL)->hash_lock);        \
  209.             else read_unlock(&(DETAIL)->hash_lock);                \
  210.             if (set)                            \
  211.                 cache_fresh(DETAIL, &tmp->MEMBER, item->MEMBER.expiry_time); \
  212.             if (set && !INPLACE && new) cache_fresh(DETAIL, &new->MEMBER, 0);    \
  213.             if (new) (DETAIL)->cache_put(&new->MEMBER, DETAIL);        \
  214.             return tmp;                            \
  215.         }                                    \
  216.     }                                        \
  217.     /* Didn't find anything */                            \
  218.     if (new) {                                    \
  219.         INIT;                                    \
  220.         new->MEMBER.next = *head;                        \
  221.         *head = &new->MEMBER;                            \
  222.         (DETAIL)->entries ++;                            \
  223.         set_bit(CACHE_HASHED, &new->MEMBER.flags);                \
  224.         if (set) {                                \
  225.             tmp = new;                            \
  226.             if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags))        \
  227.                 set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);        \
  228.             else {UPDATE;}                            \
  229.         }                                    \
  230.     }                                        \
  231.     if (set||new) write_unlock(&(DETAIL)->hash_lock);                \
  232.     else read_unlock(&(DETAIL)->hash_lock);                        \
  233.     if (new && set)                                    \
  234.         cache_fresh(DETAIL, &new->MEMBER, item->MEMBER.expiry_time);        \
  235.     if (new)                                           \
  236.         return new;                                \
  237.     new = kmalloc(sizeof(*new), GFP_KERNEL);                    \
  238.     if (new) {                                    \
  239.         cache_init(&new->MEMBER);                        \
  240.         goto retry;                                \
  241.     }                                        \
  242.     return NULL;                                    \
  243. }
  244.  
  245. #define DefineSimpleCacheLookup(STRUCT,INPLACE)    \
  246.     DefineCacheLookup(struct STRUCT, h, STRUCT##_lookup, (struct STRUCT *item, int set), /*no setup */,    \
  247.               & STRUCT##_cache, STRUCT##_hash(item), STRUCT##_match(item, tmp),\
  248.               STRUCT##_init(new, item), STRUCT##_update(tmp, item),INPLACE)
  249.  
  250. #define cache_for_each(pos, detail, index, member)                         \
  251.     for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ;        \
  252.          ({if (index==0)read_unlock(&(detail)->hash_lock); index--;});            \
  253.         )                                        \
  254.         for (pos = container_of((detail)->hash_table[index], typeof(*pos), member);    \
  255.              &pos->member;                                \
  256.              pos = container_of(pos->member.next, typeof(*pos), member))
  257.  
  258.          
  259.  
  260. extern void cache_clean_deferred(void *owner);
  261.  
  262. static inline struct cache_head  *cache_get(struct cache_head *h)
  263. {
  264.     atomic_inc(&h->refcnt);
  265.     return h;
  266. }
  267.  
  268.  
  269. static inline int cache_put(struct cache_head *h, struct cache_detail *cd)
  270. {
  271.     atomic_dec(&h->refcnt);
  272.     if (!atomic_read(&h->refcnt) &&
  273.         h->expiry_time < cd->nextcheck)
  274.         cd->nextcheck = h->expiry_time;
  275.     if (!test_bit(CACHE_HASHED, &h->flags) &&
  276.         !atomic_read(&h->refcnt))
  277.         return 1;
  278.  
  279.     return 0;
  280. }
  281.  
  282. extern void cache_init(struct cache_head *h);
  283. extern void cache_fresh(struct cache_detail *detail,
  284.             struct cache_head *head, time_t expiry);
  285. extern int cache_check(struct cache_detail *detail,
  286.                struct cache_head *h, struct cache_req *rqstp);
  287. extern void cache_flush(void);
  288. extern void cache_purge(struct cache_detail *detail);
  289. #define NEVER (0x7FFFFFFF)
  290. extern void cache_register(struct cache_detail *cd);
  291. extern int cache_unregister(struct cache_detail *cd);
  292.  
  293. extern void qword_add(char **bpp, int *lp, char *str);
  294. extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
  295. extern int qword_get(char **bpp, char *dest, int bufsize);
  296.  
  297. static inline int get_int(char **bpp, int *anint)
  298. {
  299.     char buf[50];
  300.     char *ep;
  301.     int rv;
  302.     int len = qword_get(bpp, buf, 50);
  303.     if (len < 0) return -EINVAL;
  304.     if (len ==0) return -ENOENT;
  305.     rv = simple_strtol(buf, &ep, 0);
  306.     if (*ep) return -EINVAL;
  307.     *anint = rv;
  308.     return 0;
  309. }
  310.  
  311. static inline time_t get_expiry(char **bpp)
  312. {
  313.     int rv;
  314.     if (get_int(bpp, &rv))
  315.         return 0;
  316.     if (rv < 0)
  317.         return 0;
  318.     return rv;
  319. }
  320.  
  321. #endif /*  _LINUX_SUNRPC_CACHE_H_ */
  322.